#include "appender_console.h"

#include "formater_pattern.h"

namespace afcore {
namespace log {

template<typename ConsoleMutex>
CAppenderConsoleBase<ConsoleMutex>::CAppenderConsoleBase(FILE* file)
  : mutex_(ConsoleMutex::mutex())
  , file_(file)
  , formatter_(std::make_unique<CFormaterPattern>()) {
}

template<typename ConsoleMutex>
void CAppenderConsoleBase<ConsoleMutex>::Log(const SLogMessage& msg) {
  std::lock_guard<RMutex> lock(mutex_);
  RMemoryBuf formatted;
  formatter_->Format(msg, formatted);
  fwrite(formatted.data(), sizeof(char), formatted.size(), file_);
  fflush(file_);
}

template<typename ConsoleMutex>
void CAppenderConsoleBase<ConsoleMutex>::Flush() {
  std::lock_guard<RMutex> lock(mutex_);
  fflush(file_);
}

template<typename ConsoleMutex>
void CAppenderConsoleBase<ConsoleMutex>::SetPattern(const std::string& pattern) {
  std::lock_guard<RMutex> lock(mutex_);
  formatter_ = std::unique_ptr<CFormatter>(new CFormaterPattern(pattern));
}

template<typename ConsoleMutex>
void CAppenderConsoleBase<ConsoleMutex>::SetFormatter(RFormatterUptr formatter) {
  std::lock_guard<RMutex> lock(mutex_);
  formatter_ = std::move(formatter);
}

template<typename ConsoleMutex>
CAppenderConsoleStdout<ConsoleMutex>::CAppenderConsoleStdout()
  : CAppenderConsoleBase<ConsoleMutex>(stdout) {
}

template<typename ConsoleMutex>
CAppenderConsoleStdErr<ConsoleMutex>::CAppenderConsoleStdErr()
  : CAppenderConsoleBase<ConsoleMutex>(stderr) {
}

template class CAppenderConsoleBase<SConsoleMutex>;
template class CAppenderConsoleBase<SConsoleNullMutex>;
template class CAppenderConsoleStdout<SConsoleMutex>;
template class CAppenderConsoleStdout<SConsoleNullMutex>;
template class CAppenderConsoleStdErr<SConsoleMutex>;
template class CAppenderConsoleStdErr<SConsoleNullMutex>;

} // !namespace log

using namespace log;

template<typename Factory>
std::shared_ptr<CLogger> ConsoleStdout_MT(const std::string &logger_name) {
  return Factory::template Create<RAppenderConsoleStdout_MT>(logger_name);
}

template<typename Factory>
std::shared_ptr<CLogger> ConsoleStdout_ST(const std::string &logger_name) {
  return Factory::template Create<RAppenderConsoleStdout_ST>(logger_name);
}

template<typename Factory>
std::shared_ptr<CLogger> ConsoleStderr_MT(const std::string &logger_name) {
  return Factory::template Create<RAppenderConsoleStdErr_MT>(logger_name);
}

template<typename Factory>
std::shared_ptr<CLogger> ConsoleStderr_ST(const std::string &logger_name) {
  return Factory::template Create<RAppenderConsoleStdErr_ST>(logger_name);
}

template AFCORE_COMMON_API std::shared_ptr<CLogger> ConsoleStdout_MT(const std::string &);
template AFCORE_COMMON_API std::shared_ptr<CLogger> ConsoleStdout_ST(const std::string &);
template AFCORE_COMMON_API std::shared_ptr<CLogger> ConsoleStderr_MT(const std::string &);
template AFCORE_COMMON_API std::shared_ptr<CLogger> ConsoleStderr_ST(const std::string &);

} // !namespace afcore